/******************************************************************************
 *
 *  Copyright (C) 2011-2012 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#include "ProtoDispBluetoothHci.h"
#include <cutils/log.h>
#include "_OverrideLog.h"
#include "nfc_target.h"

extern uint8_t* HCIDisp1(char* p_descr, uint8_t* p_data);
extern uint32_t ScrProtocolTraceFlag;
#define HCI_GEN_TRACE \
  (TRACE_CTRL_GENERAL | TRACE_LAYER_HCI | TRACE_ORG_PROTO_DISP | hci_trace_type)
static uint8_t hci_trace_type = 0;
static char* modes_str[] = {"No sleep mode",
                            "UART",
                            "UART with messaging",
                            "USB",
                            "H4IBSS",
                            "USB with host wake",
                            "SDIO",
                            "UART CS-N",
                            "SPI",
                            "H5",
                            "H4DS",
                            "",
                            "UART with BREAK"};
static uint8_t* p_end_hci = NULL;
static uint8_t* HCIDisp1Ext(char* p_descr, uint8_t* p_data, char* p_ext);
static void disp_sleepmode(uint8_t* p);
static void disp_sleepmode_evt(uint8_t* p);

///////////////////////////////////////////
///////////////////////////////////////////

uint8_t* HCIDisp1Ext(char* p_descr, uint8_t* p_data, char* p_ext) {
  if (p_data == p_end_hci) return p_data;

  char buff[200];

  sprintf(buff, "%40s : %u (0x%02x): %s", p_descr, *p_data, *p_data, p_ext);

  ScrLog(HCI_GEN_TRACE, "%s", buff);
  return (p_data + 1);
}

/*******************************************************************************
**
** Function         disp_sleepmode
**
** Description      Displays VSC sleep mode
**
** Returns          none.
**
*******************************************************************************/
void disp_sleepmode(uint8_t* p) {
  hci_trace_type = TRACE_TYPE_CMD_TX;
  ScrLog(HCI_GEN_TRACE, "--");
  int len = p[2];
  ScrLog(HCI_GEN_TRACE,
         "SEND Command to HCI.  Name: Set_Sleepmode_Param   (Hex Code: 0xfc27  "
         "Param Len: %d)",
         len);
  p += 3;
  p_end_hci = p + len;
  p = HCIDisp1Ext("Sleep_Mode", p, (*p <= 12) ? modes_str[*p] : "");
  p = HCIDisp1("Idle_Threshold_Host", p);
  p = HCIDisp1("Idle_Threshold_HC", p);
  p = HCIDisp1Ext("BT_WAKE_Active_Mode", p,
                  (*p == 0) ? "Active Low" : ((*p == 1) ? "Active High" : ""));
  p = HCIDisp1Ext("HOST_WAKE_Active_Mode", p,
                  (*p == 0) ? "Active Low" : ((*p == 1) ? "Active High" : ""));
  p = HCIDisp1("Allow_Host_Sleep_During_SCO", p);
  p = HCIDisp1("Combine_Sleep_Mode_And_LPM", p);
  p = HCIDisp1("Enable_Tristate_Control_Of_UART_Tx_Line", p);
  p = HCIDisp1Ext("Active_Connection_Handling_On_Suspend", p,
                  (*p == 0)
                      ? "Maintain connections; sleep when timed activity allows"
                      : ((*p == 1) ? "Sleep until resume is detected" : ""));
  p = HCIDisp1("Resume_Timeout", p);
  p = HCIDisp1("Enable_BREAK_To_Host", p);
  p = HCIDisp1("Pulsed_HOST_WAKE", p);

  ScrLog(HCI_GEN_TRACE, "--");
}

/*******************************************************************************
**
** Function         disp_sleepmode_evt
**
** Description      Displays HCI comand complete event for VSC sleep mode.
**
** Returns          none.
**
*******************************************************************************/
void disp_sleepmode_evt(uint8_t* p) {
  uint8_t len = p[1], status = p[5];

  hci_trace_type = TRACE_TYPE_EVT_RX;
  ScrLog(HCI_GEN_TRACE, "--");
  ScrLog(HCI_GEN_TRACE,
         "RCVD Event from HCI. Name: HCI_Command_Complete  (Hex Code: 0x0e  "
         "Param Len: %d)",
         len);

  p = HCIDisp1("Num HCI Cmd Packets", p + 2);
  ScrLog(HCI_GEN_TRACE, "%40s : 0xfc27  (Set_Sleepmode_Param)", "Cmd Code");
  ScrLog(HCI_GEN_TRACE, "%40s : %d (0x%02x) %s", "Status", status, status,
         (status == 0) ? "Success" : "");
  ScrLog(HCI_GEN_TRACE, "--");
}

/*******************************************************************************
**
** Function         ProtoDispBluetoothHciCmd
**
** Description      Display a HCI command string
**
** Returns:
**                  Nothing
**
*******************************************************************************/
void ProtoDispBluetoothHciCmd(NFC_HDR* p_buf) {
  if (!(ScrProtocolTraceFlag & SCR_PROTO_TRACE_HCI_SUMMARY)) return;
  uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
  if (*(p) == 0x27 && *(p + 1) == 0xfc)  // opcode sleep mode
  {
    disp_sleepmode(p);
  }
}

/*******************************************************************************
**
** Function         ProtoDispBluetoothHciEvt
**
** Description      display a NCI event
**
** Returns:
**                  Nothing
**
*******************************************************************************/
void ProtoDispBluetoothHciEvt(NFC_HDR* pBuffer) {
  if (!(ScrProtocolTraceFlag & SCR_PROTO_TRACE_HCI_SUMMARY)) return;

  uint8_t* p = (uint8_t*)(pBuffer + 1) + pBuffer->offset;
  if (*p == 0x0e)  // command complete
  {
    if (*(p + 1) == 4)  // length
    {
      if (*(p + 3) == 0x27 && *(p + 4) == 0xfc)  // opcode 0x27fc (sleep mode)
      {
        disp_sleepmode_evt(p);
      }
    }
  }
}
